package com.bulletflash.dynamics {
	
	import flash.geom.Vector3D;

	import com.bulletflash.btBase;
	import com.bulletflash.math.btVector3;
	import com.bulletflash.data.btCollisionFlags;

	public class btDynamicsWorld extends btBase
	{
		private static var currentDynamicsWorld : btDynamicsWorld;
		
		private var m_gravity:btVector3;
		private var m_rigidBodies:Vector.<btRigidBody>;
		private var m_nonStaticRigidBodies:Vector.<btRigidBody>;
		
		public static function getInstance() : btDynamicsWorld
		{
			if (!currentDynamicsWorld) {
				trace("version: BulletFlash v0.55 alpha (16-5-2011)");
				currentDynamicsWorld = new btDynamicsWorld();
			}
			return currentDynamicsWorld;
		}
		
		public function btDynamicsWorld()
		{
			btBase.initialize();
			
			m_rigidBodies = new Vector.<btRigidBody>();
			m_nonStaticRigidBodies = new Vector.<btRigidBody>();
		}
		
		//init the physics world with btDbvtBroadphase
		//refer to http://bulletphysics.org/mediawiki-1.5.8/index.php/Broadphase
		public function initWithDbvtBroadphase():void {
			pointer = bullet.createDiscreteDynamicsWorldWithDbvtMethod();
			m_gravity = new btVector3(pointer + 224);
		}
		
		//init the physics world with btAxisSweep3
		//refer to http://bulletphysics.org/mediawiki-1.5.8/index.php/Broadphase
		public function initWithAxisSweep3(worldAabbMin:Vector3D, worldAabbMax:Vector3D):void {
			pointer = bullet.createDiscreteDynamicsWorldWithAxisSweep3Method(worldAabbMin.x, worldAabbMin.y, worldAabbMin.z, worldAabbMax.x, worldAabbMax.y, worldAabbMax.z);
			m_gravity = new btVector3(pointer + 224);
		}
		
		//add a rigidbody to physics world
		public function addRigidBody(body:btRigidBody):void {
			bullet.addBodyMethod(body.pointer);
			
			if (body.collisionFlags != btCollisionFlags.CF_STATIC_OBJECT) {
				if (m_nonStaticRigidBodies.indexOf(body) < 0) {
					m_nonStaticRigidBodies.push(body);
				}
			}
			if (m_rigidBodies.indexOf(body) < 0) {
				m_rigidBodies.push(body);
			}
		}
		
		//add a rigidbody to physics world with group and mask
		//refer to: http://bulletphysics.org/mediawiki-1.5.8/index.php/Collision_Filtering
		public function addRigidBodyWithGroup(body:btRigidBody, group:int, mask:int):void {
			bullet.addBodyWithGroupMethod(body.pointer, group, mask);
			
			if (body.collisionFlags != btCollisionFlags.CF_STATIC_OBJECT) {
				if (m_nonStaticRigidBodies.indexOf(body) < 0) {
					m_nonStaticRigidBodies.push(body);
				}
			}
			if (m_rigidBodies.indexOf(body) < 0) {
				m_rigidBodies.push(body);
			}
		}
		
		//remove a rigidbody from physics world
		public function removeRigidBody(body:btRigidBody):void {
			bullet.removeBodyMethod(body.pointer);
			
			if (m_nonStaticRigidBodies.indexOf(body) >= 0) {
				m_nonStaticRigidBodies.splice(m_nonStaticRigidBodies.indexOf(body), 1);
			}
			if (m_rigidBodies.indexOf(body) >= 0) {
				m_rigidBodies.splice(m_rigidBodies.indexOf(body), 1);
			}
		}
		
		//get the gravity of physics world
		public function get gravity():Vector3D {
			return m_gravity.v3d;
		}
		
		//set the gravity of physics world
		public function set gravity(g:Vector3D):void {
			m_gravity.v3d = g;
			for each(var body:btRigidBody in m_nonStaticRigidBodies) {
				body.gravity = g;
			}
		}
		
		//get all rigidbodies
		public function get rigidBodies():Vector.<btRigidBody> {
			return m_rigidBodies;
		}
		
		//get all non static rigidbodies
		public function get nonStaticRigidBodies():Vector.<btRigidBody> {
			return m_nonStaticRigidBodies;
		}
		
		//set physics world scaling
		public function set scaling(v:Number):void {
			_scaling = v;
		}
		
		//get physics world scaling
		public function get scaling():Number {
			return _scaling;
		}
		
		//set time step and simulate the physics world
		//refer to: http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_the_World
		public function step(timeStep:Number, maxSubSteps:int = 1, fixedTimeStep:Number = 1.0 / 60) : void
		{
			bullet.stepMethod(timeStep, maxSubSteps, fixedTimeStep);
			
			for each(var body:btRigidBody in m_nonStaticRigidBodies) {
				body.updateTransform();
			}
		}
	}
}